#include "tio.h"
#include <string.h>
#include <math.h>
#include "rtdev/tio_intf_c.h"
#include "jkutil/bitdataop.h"
#include "log/zuclog.h"
#include "rtbus/rtbus.h"
#include "tio_gripper.h"
#include "rs485cmdque.h"
#include "rtbus/rtbus.h"

#define TIO_DEBUG(fmt, ...) zuclog_debug("TIO", fmt, ##__VA_ARGS__)
#define TIO_INFO(fmt, ...) zuclog_info("TIO", fmt, ##__VA_ARGS__)

static const uint8_t RS_CHN1 = 1;
static const uint8_t RS_CHN2 = 2;
static const uint8_t RS_CHNS = 3;

static rtdev::TIO tio_;

rtdev::TIO::TIO() : RtDev(DEV_TIO)
{
    slave_id_ = 0xFF;
    COMMU_WATCHDOG_DEFAULT_CNT = TIO_CONNECT_WATCHDOG;
}

rtdev::TIO::~TIO() {}
int rtdev::TIO::boot_init()
{
    bus_id_ = -1;
    comm_jkcan_map();
    return 0;
}
void rtdev::TIO::update() { RtDev::update(); }

void rtdev::TIO::action_when_online()
{
    // ATOM 机器人发现，TIO第一次上电后，查询不到东西；会再次掉线、上线； 故TIO 上线后再查询 TIO版本,
    query_Tio_version();
}

void rtdev::TIO::reset_tio()
{
    memset(&rs485_setting_, 0, sizeof(RS485Setting));
    memset(&tio_rs485_RTU_msg_, 0, sizeof(RS485RTUMsg) * 3);
    for (size_t i = 0; i < MAX_RS485_CHANNEL; i++) { rs485_trans_resp_msg_[i].clear(); }
    tio_status_.tio_version = 0;     // 清除版本信息
    tio_gripper_reset_send_state();  // 清楚TIO发送状态，以便上电后重新开始刷新
}

void rtdev::TIO::comm_read_TIO_key(uint8_t data)
{
    keep_alive();

    bool UIKey_free = tio_status_.UIKey_free;
    bool UIKey_point = tio_status_.UIKey_point;
    bool UIKey_pause_resume = tio_status_.UIKey_pause_resume;
    bool UIKey_custome = tio_status_.UIKey_custome;

    tio_status_.UIKey_free = getBit(&data, UIKEY_BIT_FREE_REQ);
    tio_status_.UIKey_point = getBit(&data, UIKEY_BIT_POINT_REQ);
    tio_status_.UIKey_pause_resume = getBit(&data, UIKEY_BIT_PAUSE_RESUME_REQ);
    tio_status_.UIKey_custome = getBit(&data, UIKEY_BIT_CUSTOME);

    if (UIKey_free != tio_status_.UIKey_free)
    {
        TIO_DEBUG("Key Free change from %d to %d", UIKey_free, tio_status_.UIKey_free);
    }
    if (UIKey_point != tio_status_.UIKey_point)
    {
        TIO_DEBUG("Key_point change from %d to %d", UIKey_point, tio_status_.UIKey_point);
    }
    if (UIKey_pause_resume != tio_status_.UIKey_pause_resume)
    {
        TIO_DEBUG("Key_pause_resume change from %d to %d", UIKey_pause_resume, tio_status_.UIKey_pause_resume);
    }
    if (UIKey_custome != tio_status_.UIKey_custome)
    {
        TIO_DEBUG("Key_custome change from %d to %d", UIKey_custome, tio_status_.UIKey_custome);
    }
}

void rtdev::TIO::comm_read_TIO_AI1(uint16_t data) { tio_status_.AI[0] = data; }

void rtdev::TIO::comm_read_TIO_AI2(uint16_t data)
{
    if ((tio_status_.tio_version & 0xFFFF) < 0x0300)
    {
        return;
    }
    tio_status_.AI[1] = data;
}

void rtdev::TIO::comm_read_TIO_RGB(uint8_t data)
{
    tio_status_.Lamp_color = (data >> 4) & 0x0F;
    tio_status_.is_overload = Util::get_bit(&data, 0) ? 1 : 0;
}

bool rtdev::TIO::collect_frame(uint8_t chn, uint8_t* data, uint8_t len)
{
    uint8_t whole_frame_size = data[0];
    uint8_t cur_frame_id = data[1];  // 从1计数

    if (cur_frame_id >= MAX_RS485_FRAME_SIZE)
    {
        memset(&tio_rs485_RTU_msg_[chn], 0, sizeof(RS485RTUMsg));
        return false;
    }

    // 如果 大标号先到， 假定为错误帧； 重复标号 假定为错误帧
    if (tio_rs485_RTU_msg_[chn].is_frame_part_in[cur_frame_id])
    {
        memset(&tio_rs485_RTU_msg_[chn], 0, sizeof(RS485RTUMsg));
        return false;
    }
    else
    {
        for (int i = 1; i < cur_frame_id; i++)
        {
            if (tio_rs485_RTU_msg_[chn].is_frame_part_in[i])
            {
                memset(&tio_rs485_RTU_msg_[chn], 0, sizeof(RS485RTUMsg));
                return false;
            }
        }
    }

    tio_rs485_RTU_msg_[chn].is_frame_part_in[cur_frame_id] = true;
    int data_index = 0;
    for (uint8_t i = 2; i < len; i++)  // 有效数据从第三字节开始
    {
        data_index = 6 * (cur_frame_id - 1) + i - 2;
        tio_rs485_RTU_msg_[chn].tio_rs485_buf[data_index] = data[i];
        tio_rs485_RTU_msg_[chn].data_len++;
    }

    for (int i = 1; i < whole_frame_size; i++)
    {
        if (!tio_rs485_RTU_msg_[chn].is_frame_part_in[i])
        {
            // 并非所有数据ready
            return false;
        }
    }
    return true;
}

void rtdev::TIO::comm_read_RS485_chn(uint8_t chn, uint8_t* data, uint8_t len)
{
    if (!collect_frame(chn, data, len))
    {
        return;
    }
    // 数据ready
    if (rs485_setting_.rs485_mode_Cfg[chn] == RS485_SENSOR)
    {
        tio_sensor_.comm_read_sensor_data(tio_rs485_RTU_msg_[chn].tio_rs485_buf, tio_rs485_RTU_msg_[chn].data_len);
    }
    else
    {
        proc_Rs485_response_data(chn, tio_rs485_RTU_msg_[chn].tio_rs485_buf, tio_rs485_RTU_msg_[chn].data_len);
    }
    memset(&tio_rs485_RTU_msg_[chn], 0, sizeof(RS485RTUMsg));
}

void rtdev::TIO::comm_read_RS485_inner_sensor(uint8_t* data, uint8_t len)
{
    if (!collect_frame(2, data, len))
    {
        return;
    }
    tio_sensor_.comm_read_sensor_data(tio_rs485_RTU_msg_[2].tio_rs485_buf, tio_rs485_RTU_msg_[2].data_len);
    memset(&tio_rs485_RTU_msg_[2], 0, sizeof(RS485RTUMsg));
}

int rtdev::TIO::proc_Rs485_response_data(uint8_t chn, uint8_t* buf, int len)
{
    int i = 0, j = 0;

    if (rs485_setting_.rs485_mode_Cfg[chn] == RS485_RTU)
    {
        // rtu data, 需要删除对应通道的指令
        RSRTUCMD* rsRtuCmd = RsCmdQuePeek();
        if (!rsRtuCmd)
        {
            return 0;
        }
        if (rsRtuCmd->type == 0)
        {  // status
            GripperStateUnit* gripper_sig = checkGripperSigByName(rsRtuCmd->sigName);
            if (gripper_sig)
            {
                RSRTUCMD temp;
                RsCmdDequeue(&temp);  // 确认为信号量实际返回，再删除

                gripper_sig->count--;  // 带接收指令
                u_int8_t slaveId = buf[0], funcCode = buf[1];
                if (gripper_sig->slaveId == slaveId)
                {
                    if (gripper_sig->type == funcCode)
                    {
                        int tempVal = 0;
                        for (j = 0; j < buf[2]; j++)
                        {  // buf[2]: dataLen
                            tempVal = (tempVal << 8) + buf[3 + j];
                        }
                        gripper_sig->value = tempVal;
                        gripper_sig->commu_state = GRIPPER_WAITING_TO_SEND_NORMAL;
                        //rtapi_print("response obtained: value = %d\n", gripperState[i].value);
                    }
                    else if (funcCode & 0x80)
                    {
                        set_gripper_error(gripper_sig, 2);
                    }
                    else
                    {
                    }
                }
                else
                {
                    set_gripper_error(gripper_sig, 2);
                }
            }
        }
    }
    else if (rs485_setting_.rs485_mode_Cfg[chn] == RS485_TRANS)
    {
        for (int i = 0; i < len; i++)
        {
            if (rs485_trans_resp_msg_[chn].size() > TIO_RS485_MAX_BUFFER)
            {
                rs485_trans_resp_msg_[chn].pop_front();
            }
            rs485_trans_resp_msg_[chn].push_back(buf[i]);
        }
    }
    else
    {
        return -1;
    }
    return 0;
}

int rtdev::TIO::get_sdo(uint32_t obj_id, std::function<int(uint8_t*, int)> cb, int timeout, int retry)
{
    if (sim_flag_)
        return 0;
    if (!master_)
        return -1;
    return master_->get_sdo(slave_id_, obj_id, cb, timeout, retry);
}

int rtdev::TIO::set_sdo(uint32_t obj_id, uint8_t* val, int size, std::function<int(uint8_t*, int)> cb, int timeout, int retry)
{
    if (sim_flag_)
        return 0;
    if (!master_)
        return -1;
    return master_->set_sdo(slave_id_, obj_id, (uint8_t*)val, size, cb, timeout, retry);
}

int rtdev::TIO::tio_set_dout(uint8_t index, uint8_t dout)
{
    if (dout < 0 || dout > 1 || index < 0 || index > 1)
    {
        return -1;
    }
    uint8_t mask = 1 << index;
    if (dout)
    {
        tio_setting_.DO_buffer |= mask;
    }
    else
    {
        tio_setting_.DO_buffer &= ~mask;
    }
    return 0;
}

int rtdev::TIO::tio_set_lamp(TIOLampColor color)
{
    tio_setting_.Lamp_color = color;
    return 0;
}

rtdev::TIO* rtdev::get_TIO() { return &tio_; }

int rtdev::TIO::comm_write_RS485_chn(uint8_t chn, uint8_t* data)
{
    // organize the can message
    // int enable[2] = {1, 1};
    checkSignalUpdate(rs485_setting_.rs485_chn_ena, rs485_setting_.rs485_mode_Cfg);  // 检查是否有信号量需要添加进来

    if (!RsCmdQueIsEmpty())
    {
        int frameNum;
        RSRTUCMD* cmdToSend = RsCmdQuePeek();
        if (cmdToSend->type == RTU_TYPE && cmdToSend->state == WAITING_SEND)
        {                  // signal state query
            frameNum = 1;  // 信号量指令一包发完 @FIXME liwang 支持一次查询多个地址，则可能不止1包数据
            GripperStateUnit* gripper_sig = checkGripperSigByName(cmdToSend->sigName);
            if (gripper_sig)
            {
                if (gripper_sig->chnId != chn)
                {
                    return 0;
                }
                data[0] = frameNum;  // total frame num
                data[1] = frameNum;  // current frame num
                data[2] = gripper_sig->slaveId;
                data[3] = gripper_sig->type;  // function code
                data[4] = ((gripper_sig->addr >> 8) & 0xFF);
                data[5] = (gripper_sig->addr & 0xFF);
                data[6] = 0x00;
                data[7] = 0x01;  // 读取数据个数
                return 8;
            }
            else
            {
                // 信号已被删除, 相应更新指令也不需要处理了
                RSRTUCMD temp;
                RsCmdDequeue(&temp);
            }
        }
        else if (cmdToSend->type == INST_TYPE && cmdToSend->state == WAITING_SEND)  // instaneous command
        {
            if (cmdToSend->instCmd.chnId != chn)
            {
                return 0;
            }
            if (rs485_setting_.rs485_mode_Cfg[cmdToSend->instCmd.chnId] == 1)
            {
                // 透传数据，直接删除立即指令，返回数据储存于消息队列中
                RSRTUCMD cmd;
                RsCmdDequeue(&cmd);
            }
            cmdToSend->state = WIATING_REC;  // 等待接收，计数40个周期，后报超时

            for (int i = 0; i < cmdToSend->instCmd.cmdLen; i++) { data[i] = cmdToSend->instCmd.cmdData[i]; }
            return cmdToSend->instCmd.cmdLen;
        }
    }
    return 0;
}

void rtdev::TIO::set_gripper_error(GripperStateUnit* gripper_sig, int type)
{
    if (gripper_sig->commu_state != GRIPPER_WAITING_REC_ERROR && gripper_sig->commu_state != GRIPPER_WAITING_TO_SEND_ERROR)
    {
        // @FIXME liwang 需要对外报错
        switch (type)
        {
        case 1: {
            char msg[128];
            // sprintf(msg, "#{\"fixed_key\":[\"%s\"]}", gripper_sig->sigName);
            // reportError(TIO_RSCMD_RESPONSE_TIMEOUT, "command response timeout: sig = %s %s", gripper_sig->sigName, msg);
            // rtapi_print("command response timeout: sig name = %s\n", gripper_sig->sigName);
            break;
        }
        default:
            // rtapi_print("Gripper Unknow error!\n");
            break;
        }
    }
    gripper_sig->commu_state = GRIPPER_WAITING_TO_SEND_ERROR;  // 接收完成发生错误
}

/**
 * @brief check the timeouted RS485 command or query
 *
 */
void rtdev::TIO::check_tio_cmd_timeout()
{
    if (!RsCmdQueIsEmpty())
    {
        RSRTUCMD* cmdToSend = RsCmdQuePeek();
        if (cmdToSend->state == WIATING_REC)
        {
            cmdToSend->timeout_count++;
        }

        if (cmdToSend->timeout_count > 20)
        {
            RSRTUCMD abortCmd;
            RsCmdDequeue(&abortCmd);
            if (abortCmd.type == RTU_TYPE)
            {
                GripperStateUnit* gripper_sig = checkGripperSigByName(abortCmd.sigName);
                if (gripper_sig)
                {
                    gripper_sig->count--;
                    if (gripper_sig)
                    {
                        set_gripper_error(gripper_sig, 1);
                    }
                }
            }
        }
    }
}

int tio_cmd_reset()
{
    RsCmdQueReset();
    tio_gripper_reset_send_state();  // 清楚TIO发送状态，以便上电后重新开始刷新
    return 0;
}

int rtdev::TIO::get_rs485_responce_msg(int chn, int len, uint8_t* msg)
{
    if (chn < 0 || chn > MAX_RS485_CHANNEL)
    {
        return -1;
    }
    int i = 0;
    for (i = 0; i < len; i++)
    {
        if (rs485_trans_resp_msg_[chn].empty())
        {
            return i;
        }
        msg[i] = rs485_trans_resp_msg_[chn].front();
        rs485_trans_resp_msg_[chn].pop_front();
    }
    return i;
}

// TIO SDO 数据从第四位开始，长度为4
template <typename T> static T get_data(uint8_t* data, uint8_t length)
{
    T res = 0;
    for (int i = 0; i < length; i++)
    {
        res = res << 8;
        res += data[3 + i];
    }
    return res;
}

#define FUNC_QUERY_OBJECT(func_name, obj_id, val, len)           \
    int rtdev::TIO::func_name()                                  \
    {                                                            \
        get_sdo(                                                 \
            obj_id,                                              \
            [this](uint8_t* rx_data, int s) -> int {             \
                if (s < 7)                                       \
                {                                                \
                    return -1;                                   \
                }                                                \
                val = get_data<int>(rx_data, len);               \
                TIO_DEBUG("Get TIO object %X: %d", obj_id, val); \
                return 0;                                        \
            },                                                   \
            80,                                                  \
            10);                                                 \
        return 0;                                                \
    }

#define FUNC_SET_OBJECT(func_name, object_id, len)                                       \
    int rtdev::TIO::func_name(uint32_t data)                                             \
    {                                                                                    \
        set_sdo(                                                                         \
            object_id,                                                                   \
            (uint8_t*)(&data),                                                           \
            4,                                                                           \
            [this, data](uint8_t* rx_data, int size) -> int {                            \
                if (size < 7)                                                            \
                {                                                                        \
                    return -1;                                                           \
                }                                                                        \
                uint32_t data_fb = get_data<int>(rx_data, len);                          \
                TIO_DEBUG("Set TIO object %X to %d, get: %d", object_id, data, data_fb); \
                return 0;                                                                \
            },                                                                           \
            80,                                                                          \
            10);                                                                         \
        return 0;                                                                        \
    }

FUNC_SET_OBJECT(tio_setup_di_pin, OBJID_DI_CFG, 4)
FUNC_SET_OBJECT(tio_setup_do_pin, OBJID_DO_CFG, 4)
FUNC_SET_OBJECT(tio_setup_ai_pin, OBJID_AI_CFG, 4)

int rtdev::TIO::tio_set_rs485_chn_func(uint32_t chn)
{
    if (chn < 0 || chn > MAX_RS485_CHANNEL)
    {
        return -1;
    }
    set_sdo(
        OBJID_SENSOR_CHN_CFG,
        (uint8_t*)(&chn),
        4,
        [this, chn](uint8_t* rx_data, int size) -> int {
            uint32_t data_fb = get_data<int>(rx_data, 4);
            TIO_DEBUG("Set TIO object %X to %d, get: %d", OBJID_SENSOR_CHN_CFG, chn, data_fb);
            return 0;
        },
        80,
        10);
    return 0;
}

int rtdev::TIO::tio_set_vout_voltage(uint32_t data)
{
    if (data < 0 || data > 1)
    {
        return -1;
    }
    set_sdo(
        OBJID_OUT_VOLTAGE,
        (uint8_t*)(&data),
        4,
        [this, data](uint8_t* rx_data, int size) -> int {
            uint32_t data_fb = get_data<int>(rx_data, 4);
            TIO_DEBUG("Set TIO object %X to %d, get: %d", OBJID_OUT_VOLTAGE, data, data_fb);
            return 0;
        },
        80,
        10);
    return 0;
}

int rtdev::TIO::tio_set_vout_enable(uint32_t data)
{
    if (data < 0 || data > 1)
    {
        return -1;
    }
    set_sdo(
        OBJID_VOUT_ENABLE,
        (uint8_t*)(&data),
        4,
        [this, data](uint8_t* rx_data, int size) -> int {
            uint32_t data_fb = get_data<int>(rx_data, 4);
            TIO_DEBUG("Set TIO object %X to %d, get: %d", OBJID_VOUT_ENABLE, data, data_fb);
            return 0;
        },
        80,
        10);
    return 0;
}

int rtdev::TIO::query_Tio_version()
{
    get_sdo(
        OBJID_VERSION,
        [this](uint8_t* rx_data, int s) -> int {
            if (s < 4)
            {
                return -1;
            }
            hw_version_ = get_data<int>(rx_data, 2);
            sw_version_ = get_data<int>(rx_data + 2, 2);
            tio_status_.tio_version = (hw_version_ << 8) + sw_version_;
            TIO_INFO("Get TIO Version %X: %X", hw_version_, sw_version_);
            return 0;
        },
        80,
        10);
    return 0;
}

int rtdev::TIO::set_tio_rs485_chn_mode(int chn, RS485Mode mode)
{
    TIO_DEBUG("set_tio_rs485_chn_mode called: chn=%d, mode=%d\n", chn, mode);
    if (chn > 1 || chn < 0)
    {
        return -1;
    }
    if (mode < RS485Mode::RS485_RTU || mode > RS485Mode::RS485_TRANS)
    {
        return -1;
    }
    uint32_t data = mode;
    uint16_t object_id = chn ? OBJID_RS4852_COMM : OBJID_RS4851_COMM;
    set_sdo(
        object_id,
        (uint8_t*)(&data),
        4,
        [this, mode, object_id](uint8_t* rx_data, int size) -> int {
            uint32_t data_fb = get_data<int>(rx_data, 4);
            TIO_DEBUG("Set TIO object %X to %d, get: %d", object_id, mode, data_fb);
            return 0;
        },
        80,
        10);
    ;
    rs485_setting_.rs485_mode_Cfg[chn] = mode;
    return 0;
}

int rtdev::TIO::set_tio_rs485_chn_comm(int chn, int baudrate, int databit, int stopbit, char parity)
{
    TIO_INFO("set_tio_rs485_chn_comm called: chn=%d, baudrate=%d, databit=%d, stopbit=%d, parity=%d\n", chn, baudrate, databit, stopbit, parity);
    if (chn > 1 || chn < 0)
    {
        return -1;
    }
    uint32_t comm_cfg = (baudrate & 0x7FFFFF);
    if (stopbit == 2)
    {
        comm_cfg |= (2 << 23);
    }
    if (parity == 'E')
    {
        comm_cfg |= ((1 & 0x3) << 25);
    }
    else if (parity == 'O')
    {
        comm_cfg |= ((2 & 0x3) << 25);
    }
    if (databit == 9)
    {
        comm_cfg |= (1 << 27);
    }
    uint16_t object_id = chn ? OBJID_RS4852_COMM : OBJID_RS4851_COMM;
    set_sdo(
        object_id,
        (uint8_t*)(&comm_cfg),
        4,
        [this, comm_cfg, object_id](uint8_t* rx_data, int size) -> int {
            uint32_t data_fb = get_data<int>(rx_data, 4);
            TIO_DEBUG("Set TIO object %X to %d, get: %d", object_id, comm_cfg, data_fb);
            return 0;
        },
        80,
        10);
    return 0;
}
void rtdev::TIO::comm_jkcan_map()
{
    auto bus = rtbus::BusMgr::get();
    // bus->register_rx_handle(0x190, [this](uint32_t busid, uint8_t* data, size_t size) {
    //     // TIO 状态反馈
    //     if (size != 8)
    //         return -1;
    //     if ((int)busid != get_master_id() && get_master_id() != -1)
    //     {
    //         comm_jkcan_tx_map(busid);
    //     }
    //     comm_read_TIO_key(data[0]);
    //     comm_read_TIO_DI(data[1]);
    //     comm_read_TIO_DO(data[2]);
    //     uint16_t AI1 = (data[3] << 8) + data[4];
    //     uint16_t AI2 = (data[5] << 8) + data[6];
    //     comm_read_TIO_AI1(AI1);
    //     comm_read_TIO_AI2(AI2);
    //     comm_read_TIO_RGB(data[7]);
    //     return 0;
    // });
    //tio-485
    // bus->register_rx_handle(0x720, [this](uint32_t id, uint8_t* data, size_t size) {
    //     // 485_2 数据
    //     comm_read_RS485_chn(0, data, size);
    //     return 0;
    // });
    // bus->register_rx_handle(0x730, [this](uint32_t id, uint8_t* data, size_t size) {
    //     // 485_1 数据
    //     comm_read_RS485_chn(1, data, size);
    //     return 0;
    // });
    // bus->register_rx_handle(0x740, [this](uint32_t id, uint8_t* data, size_t size) {
    //     // 内嵌传感器数据
    //     comm_read_RS485_inner_sensor(data, size);
    //     return 0;
    // });
}
void rtdev::TIO::shutdown()
{
    //
    // rtbus::BusMgr::get()->unregister_tx_handle(get_master_id(), 0x721);
    // rtbus::BusMgr::get()->unregister_tx_handle(get_master_id(), 0x731);
    // rtbus::BusMgr::get()->unregister_tx_handle(get_master_id(), 0x210);

    // rtbus::BusMgr::get()->unregister_rx_handle(0x190);
    // rtbus::BusMgr::get()->unregister_rx_handle(0x720);
    // rtbus::BusMgr::get()->unregister_rx_handle(0x730);
    // rtbus::BusMgr::get()->unregister_rx_handle(0x740);
    bus_id_ = -1;
}
void rtdev::TIO::comm_jkcan_tx_map(int busid)
{
    auto bus = rtbus::BusMgr::get();
    // bus->register_tx_handle(busid, 0x721, [this](uint32_t id, uint8_t* data, size_t size) {
    //     // 485_2 控制
    //     return comm_write_RS485_chn(1, data);
    // });
    // bus->register_tx_handle(busid, 0x731, [this](uint32_t id, uint8_t* data, size_t size) {
    //     // 485_1 控制
    //     return comm_write_RS485_chn(0, data);
    // });
    // bus->register_tx_handle(busid, 0x210, [this](uint32_t id, uint8_t* data, size_t size) {
    //     // TIO 状态 指令
    //     memset(data, 0, 8 * sizeof(uint8_t));
    //     TIOSetting setting;
    //     comm_write_TIO_Setting(&setting);
    //     data[0] = setting.DO_buffer;
    //     data[1] = setting.Lamp_color;
    //     data[2] = setting.AI_range;
    //     return 3;
    // });
    // set_master(busid);
}
